package com.neusoft.neuiotms.dcom.service.malfunction.impl;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityNotFoundException;
import javax.transaction.Transactional;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.neusoft.bizcore.activiti.service.ProcessInstanceService;
import com.neusoft.bizcore.auth.common.bean.UserBean;
import com.neusoft.bizcore.file.converter.MongoFileConverter;
import com.neusoft.bizcore.file.dto.FileDTO;
import com.neusoft.bizcore.file.model.FileDocument;
import com.neusoft.bizcore.file.service.FileService;
import com.neusoft.bizcore.notice.constant.NoticeConsts;
import com.neusoft.bizcore.notice.notification.dto.NoticeRecordDTO;
import com.neusoft.bizcore.notice.notification.dto.NoticeRecordSystemDTO;
import com.neusoft.bizcore.web.constant.ExceptionConstants;
import com.neusoft.bizcore.web.exception.UnitedException;
import com.neusoft.bizcore.web.utils.JsonUtils;
import com.neusoft.neuiotms.dcom.constants.DCOMConstants;
import com.neusoft.neuiotms.dcom.converter.malfunction.MalfunctionCustomerReviewConverter;
import com.neusoft.neuiotms.dcom.dto.malfunction.MalfunctionCustomerReviewDTO;
import com.neusoft.neuiotms.dcom.model.malfunction.MalfunctionCustomerReview;
import com.neusoft.neuiotms.dcom.model.malfunction.MalfunctionFrontlineProcessingForm;
import com.neusoft.neuiotms.dcom.repository.malfunction.MalfunctionCustomerReviewAnnexRepository;
import com.neusoft.neuiotms.dcom.repository.malfunction.MalfunctionCustomerReviewRepository;
import com.neusoft.neuiotms.dcom.repository.malfunction.MalfunctionFrontlineProcessingFormRepository;
import com.neusoft.neuiotms.dcom.service.malfunction.MalfunctionCustomerReviewService;
import com.neusoft.neuiotms.micro.auth.AuthMicroService;
import com.neusoft.neuiotms.micro.notice.NoticeMicroService;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class MalfunctionCustomerReviewServiceImpl implements MalfunctionCustomerReviewService {

    @Value("${files.storage.mongodb.collection:files}")
    private String collectionName;
    @Autowired
    private MalfunctionCustomerReviewAnnexRepository customerReviewAnnexRepository;
    @Autowired
    private MalfunctionCustomerReviewRepository customerReviewRepository;
    @Autowired
    private MalfunctionCustomerReviewConverter customerReviewConverter;
    @Autowired
    private ProcessInstanceService processInstanceService;
    @Autowired
    private FileService fileService;
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private MongoFileConverter mongoFileConverter;
    @Autowired
    private GridFsTemplate gridFsTemplate;
    @Autowired
    private NoticeMicroService noticeMicroService;
    @Autowired
    private MalfunctionFrontlineProcessingFormRepository malfunctionFrontlineProcessingFormRepository;
    @Autowired
    private AuthMicroService authMicroService;

    @Transactional
    @Override
    public MalfunctionCustomerReviewDTO create(final MalfunctionCustomerReviewDTO dto, final UserBean user) {

        // 完成节点
        this.processInstanceService.complete(dto.getWorkNum(), dto.getTaskId(), user);

        // 保存操作信息
        final MalfunctionCustomerReview model = this.customerReviewConverter.toModel(dto);
        this.customerReviewRepository.save(model);

        final MalfunctionFrontlineProcessingForm frontlineProcessingForm =
                this.malfunctionFrontlineProcessingFormRepository.findTopByWorkNumOrderByIdDesc(dto.getWorkNum());
        if ((null != frontlineProcessingForm) && "serious".equals(frontlineProcessingForm.getFailureLevelCode())) {

            final Map<String, Object> queryMap = Maps.newHashMap();

            final List<String> userArray = Lists.newArrayList();
            queryMap.put("s_roleCode", "zongjian");
            final List<Map<String, Object>> leaderList = this.authMicroService.userIndex(queryMap).getData();
            leaderList.stream().forEach(e -> {
                userArray.add(e.get("username").toString());
            });
            if (userArray.size() > 0) {
                final NoticeRecordDTO notice = new NoticeRecordDTO();
                notice.setCreateTime(new Date());
                notice.setAppCode("dcom");
                notice.setType(Lists.newArrayList(NoticeConsts.INFORM_TYPE_NOTICE));
                notice.setTitle("故障工单处理完成提醒");
                final NoticeRecordSystemDTO toSystem = new NoticeRecordSystemDTO();
                toSystem.setNoticeType("故障工单处理完成提醒");
                toSystem.setUsers(userArray);
                toSystem.setContent("故障工单" + dto.getWorkNum() + ",已解决");
                notice.setSystem(toSystem);

                this.noticeMicroService.createNotification(JsonUtils.pojoToJson(notice));
                MalfunctionCustomerReviewServiceImpl.log.info("send serious work order completed notice to users: {}",
                        String.join(",", userArray));
            }
        }
        return this.customerReviewConverter.toDTO(model);

    }

    @Override
    public MalfunctionCustomerReviewDTO detail(final String workNum, final String taskId, final UserBean user) {
        MalfunctionCustomerReview model = null;
        try {
            if (StringUtils.isNotBlank(workNum) && !DCOMConstants.STR_NULL.equals(taskId)) {
                model = this.customerReviewRepository.findByWorkNumAndTaskId(workNum, taskId);
                if (model == null) {
                    // 获取前一节点的TaskID
                    final String fromProcessTaskId = this.processInstanceService.getLastTaskId(taskId, user);
                    if (fromProcessTaskId == null) {
                        return new MalfunctionCustomerReviewDTO();
                    } else {
                        model = this.customerReviewRepository.findByWorkNumAndTaskId(workNum, fromProcessTaskId);
                    }
                }
            } else if (DCOMConstants.STR_NULL.equals(taskId)) {
                model = this.customerReviewRepository.findTopByWorkNumOrderByIdDesc(workNum);
            }
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND,
                    new Object[] {workNum },
                    new Object[] {taskId });
        }
        return this.customerReviewConverter.toDTO(model);
    }

    @Override
    public FileDTO save(final MultipartFile file) {
        try {
            final String md5 = DigestUtils.md5DigestAsHex(file.getInputStream());
            FileDocument doc = this.getByMd5(md5);
            if (doc != null) {
                return this.mongoFileConverter.toDTO(doc);
            }

            doc = new FileDocument();
            doc.setName(file.getOriginalFilename());
            doc.setSize(file.getSize());
            doc.setContentType(file.getContentType());
            doc.setUploadDate(new Date());
            doc.setMd5(md5);
            final String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1);
            doc.setSuffix(suffix);

            final String fsId = this.uploadFileToGridFS(file.getInputStream(), this.createFilePath(suffix), suffix);
            doc.setFsId(fsId);
            doc = this.mongoTemplate.save(doc, this.collectionName);
            return this.mongoFileConverter.toDTO(doc);
        } catch (final IOException e) {
            MalfunctionCustomerReviewServiceImpl.log.error("", e);
        }
        return null;
    }

    @Override
    public void deleteMongoFile(final String fsId) {
        this.fileService.deleteByFsId(fsId);
        this.customerReviewAnnexRepository.deleteByFsId(fsId);

    }

    public String uploadFileToGridFS(final InputStream in, final String fileName, final String contentType) {
        this.gridFsTemplate.store(in, fileName, contentType);
        return fileName;
    }

    private FileDocument getByMd5(final String md5) {
        final Query query = new Query().addCriteria(Criteria.where("md5").is(md5));
        final FileDocument fileDocument = this.mongoTemplate.findOne(query, FileDocument.class, this.collectionName);
        return fileDocument;
    }

    private String createFilePath(final String suffix) {
        final StringBuilder id = new StringBuilder();
        id.append(String.valueOf(System.currentTimeMillis()))
                .append(String.valueOf((int) (Math.random() * 10000)))
                .append(".")
                .append(suffix);
        return id.toString();
    }

}
